/* svnNotifierTest.c
 *
 * Simple test app for the daemon. This tests the remote connectivity as
 * the client will be able to test the local connectivity.
 */

/*
 * Licensed to the ConArtist Development Team (CADT).
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 * The CADT licenses this file to you under the Apache License, 
 * Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <stdlib.h>

#include "apr_pools.h"
#include "apr_network_io.h"
#include "apr_poll.h"
#include "apr_errno.h"

#include "svnNotifier.h"

static apr_pool_t *testPool = NULL;
static apr_pollset_t *pollset = NULL;

static void reportError(const char *msg, apr_status_t rv, 
                        apr_pool_t *pool)
{
    fprintf(stderr, "%s\nError: %d\n'%s'\n", msg, rv,
            apr_psprintf(pool, "%pm", &rv));
}

static apr_status_t createSocket(const char *host, apr_port_t port,
                                 void (*func)(apr_socket_t *),
                                 apr_pool_t *pool)
{
    apr_status_t rv;
    apr_socket_t *s = NULL;
    apr_sockaddr_t *sockAddr = NULL;
    apr_pollfd_t socketPoll;

    rv = apr_socket_create(&s, APR_INET, SOCK_STREAM, APR_PROTO_TCP,
                           pool);
    if (rv != APR_SUCCESS) {
        reportError("Unable to create socket", rv, pool);
        return rv;
    }

    rv = apr_sockaddr_info_get(&sockAddr, host, APR_UNSPEC,
                               port, 0, pool);
    if (rv != APR_SUCCESS) {
        reportError("Unable to get socket info", rv, pool);
        apr_socket_close(s);
        return rv;
    }

    if ((rv = apr_socket_bind(s, sockAddr)) != APR_SUCCESS ||
        (rv = apr_socket_listen(s, 5)) != APR_SUCCESS) {
        reportError("Unable to bind or listen to socket", rv, pool);
        apr_socket_close(s);
        return rv;
    }

    socketPoll.desc_type = APR_POLL_SOCKET;
    socketPoll.reqevents = APR_POLLIN;
    socketPoll.desc.s = s;
    socketPoll.client_data = func;
    rv = apr_pollset_add(pollset, &socketPoll);
    if (rv != APR_SUCCESS) {
        reportError("Unable to add socket to pollset", rv, pool);
        return rv;
    }
    return APR_SUCCESS;
}

/* We listen on a local socket for notifications of changes via the
 * svnNotifierClient.
 */
apr_status_t setupLocalSocket(void)
{
    return APR_SUCCESS;
}

void processRemote(apr_socket_t *acceptedSocket)
{
    printf("Accepted a remote socket!\n");
}

/* We listen on port 7543 for ConArtist servers telling us they have an
 * interest in one or more repositories on this server. We capture the
 * the port they use for the request and respond on that port 
 * subsequently.
 */
apr_status_t setupListener(apr_pool_t *pool)
{
    return createSocket(NULL, SVN_NOTIFY_REMOTE, &processRemote, pool);
}

/* Invoked as 
 * svnNotifierTest <host>
 */
int main(int argc, char **argv)
{
    apr_status_t rv = 1;
    apr_sockaddr_t *them = NULL;
    apr_socket_t *sock = NULL;
    const char *host = (argc > 1 ? argv[1] : "127.0.0.1");
    char *msg = NULL;

    apr_initialize();
    if (apr_pool_create(&testPool, NULL) != APR_SUCCESS) {
        fprintf(stderr, "Unable to create a pool\n");
        exit(1);
    }
    if (apr_pollset_create(&pollset, 1, testPool, 0) != APR_SUCCESS) {
        fprintf(stderr, "Unable to create required pollset\n");
        exit(1);
    }

    fprintf(stdout, "Starting ConArtist Notification daemon test application\n");

    /* Try and create an ephemeral socket, ie one whos port number we don't
     * care about.
     */
    rv = apr_sockaddr_info_get(&them, host, APR_UNSPEC,
                               SVN_NOTIFY_REMOTE, 0, testPool);

    msg = apr_psprintf(testPool, "%pI", them);
    printf("Trying to connect to %s\n", msg);

    rv = apr_socket_create(&sock, them->family, SOCK_STREAM, 0, testPool);
    printf("Connecting... ");
    fflush(stdout);

    rv = apr_socket_connect(sock, them);
    if (rv != APR_SUCCESS)
        reportError("failed to connect", rv, testPool);
    else {
        char id[32];
        char *buffer = NULL;
        apr_size_t bytesRead = 32;
        printf("OK\n");
        buffer = apr_psprintf(testPool, "<?xml version=\"1.0\"?>"
                             "<svnNotifications><repo>"
                             "svn://localhost/test/a/b</repo>"
                             "</svnNotifications>");
        bytesRead = strlen(buffer);
        rv = apr_socket_send(sock, buffer, &bytesRead);

        bytesRead = 32;

        rv = apr_socket_recv(sock, id, &bytesRead);
        printf("id = '%s'\n", id);
    }
    
    apr_socket_close(sock);

    return (0);
}
